package crypto

import (
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"golang.org/x/crypto/argon2"
	rand2 "math/rand"
	"strings"
)

// EncryptPassword 使用 Argon2 ID 算法的标准参数对密码进行加密
// 内存消耗64MB, 1次迭代, 并行度为4, 随机的32byte salt
func EncryptPassword(password string) (cipherText string, err error) {
	salt, err := GenerateRandomBytes(16)
	if err != nil {
		return "", err
	}
	hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
	return base64.RawStdEncoding.EncodeToString(hash) + "." + base64.RawStdEncoding.EncodeToString(salt), nil
}

// ComparePassword 使用 Argon2 ID 算法的标准参数对密码进行比较
func ComparePassword(password, cipherText string) (ok bool) {
	items := strings.SplitN(cipherText, ".", 2)
	if len(items) != 2 {
		return false
	}
	hashByte, err := base64.RawStdEncoding.DecodeString(items[0])
	if err != nil {
		return false
	}
	saltByte, err := base64.RawStdEncoding.DecodeString(items[1])
	if err != nil {
		return false
	}
	hash2 := argon2.IDKey([]byte(password), saltByte, 1, 64*1024, 4, 32)
	return subtle.ConstantTimeCompare(hashByte, hash2) == 1
}

// GenerateRandomBytes 随机生成N字节数据
func GenerateRandomBytes(n uint) ([]byte, error) {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

const allAlphaNum = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func GenerateRandomAlphaNum(length int) string {
	buf := make([]byte, length)
	for i := 0; i < length; i++ {
		buf[i] = allAlphaNum[rand2.Int63()%int64(len(allAlphaNum))]
	}
	return string(buf)
}
